import json
import random
from os import abort
from datetime import datetime
from flask import request, current_app ,make_response, jsonify, session
from info import redis_store, db
from info import constants
from info.lib.yuntongxun.sms import CCP
from . import passport_bp
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET
import re
from info.models import User


@passport_bp.route("/loginout")
def loginout():
    """退出登录接口"""
    session.pop("user_id", None)
    session.pop("mobile", None)
    session.pop("nick_name", None)
    session.pop("is_admin", None)

    return jsonify(errno=RET.OK, errmsg="退出登录")



@passport_bp.route("/login", methods=["POST"])
def login():
    """登录接口"""

    # 1.获取参数 密码和手机号码
    params_dict = request.json
    mobile = params_dict.get("mobile")
    password = params_dict.get("password")
    # 2.校验参数
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")
    # 手机号码是否符合正则
    if not re.match("1[35678]\\d{9}", mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机号码格式错误")
    # 3.逻辑处理
    # 3.0 查询用户是否存在
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="从数据库查询用户异常")

    if not user:
        return jsonify(errno=RET.NODATA, errmsg="用户不存在")

    # 记录用户最后一次登录的时间
    user.last_login = datetime.now()

    # 如果在视图函数里面对数据库对象身上的属性发送了改变，需要使用commit()进行保存到数据库
    # 其实也不使用db.session.commit()方式，前提是在SQLAlchemy的配置中有设置相关配置
    # try:
    #     db.session.commit()
    # except Exception as e:
    #     current_app.logger.error(e)
    #     db.session.rollback()
    #     return jsonify(errno=RET.DBERR, errmsg="修改user模型存到数据库异常")


    # 3.1 拿到密码和用户填写的密码进行比较
    if not user.check_password(password):
        # 密码错误
        return jsonify(errno=RET.PWDERR, errmsg="密码填写错误")

    # 3.2密码正确表示登录成功 记录登录状态-session
    session["user_id"] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.mobile

    # 4.返回值处理
    return jsonify(errno=RET.OK, errmsg="登录成功")



@passport_bp.route("/register", methods=["POST"])
def register():
    """
    注册接口
    1. 获取参数 手机号码 短信验证码 密码
    2. 校验参数
        2.1 手机号码 短信验证码 密码是否为空
        2.2 手机号码是否符合正则
    3. 逻辑处理
        3.1 获取redis里面的存储的真实短信验证码
        3.2 拿用户填写的短信验证码和真实短信验证码进行比较
        3.3 如果不一致提示错误
        3.4 如果一直进行User模型的创建和属性赋值
        3.5 存储到数据库
        3.6 注册成功表示登录成功（将用户数据存储到session）
    4. 返回值处理
    """
    # 1. 获取参数 手机号码 短信验证码 密码
    params_dict = request.json
    mobile = params_dict["mobile"]
    smscode = params_dict["smscode"]
    password = params_dict["password"]
    # 2.1 手机号码 短信验证码 密码是否为空
    if not all([mobile, smscode, password]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")
    # 2.2 手机号码是否符合正则
    if not re.match("1[35678]\\d{9}", mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机号码格式错误")

    # 3.1 获取redis里面的存储的真实短信验证码
    try:
        real_sms_code = redis_store.get("mobilesms_" + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="redis中获取短信验证码出错")
    # 如果没有值表示从redis获取到一个空数据，短信验证码过期
    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg="短信验证码过期")

    # 3.2 拿用户填写的短信验证码和真实短信验证码进行比较
    if smscode != real_sms_code:
        return jsonify(errno=RET.DATAERR, errmsg="短信验证码填写错误")

    # 3.4 如果一直进行User模型的创建和属性赋值
    user = User()
    user.mobile = mobile
    # 此时还未设置昵称 使用手机号码代替
    user.nick_name = mobile
    # TODO: 设置加密密码
    user.password = password
    # 设置最后一次登录时间
    user.last_login = datetime.now()


    # 3.5 存储到数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 数据库错误进行回滚操作
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="存储user对象到mysql数据库异常")

    # 3.6 注册成功表示登录成功（将用户数据存储到session）
    session["user_id"] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.mobile

    #  4. 返回值处理
    return jsonify(errno=RET.OK, errmsg="注册成功")




@passport_bp.route("/sms_code", methods=["POST"])
def send_sms():
    """
    发送短信验证码接口
    1. 获取参数
        1.1 图片验证码真实值
        1.2 图片验证码的编号（UUID）
        1.3 手机号码
    2. 校验参数
        2.1 判断参数是否有值
        2.2 手机号码的格式进行正则匹配
    3. 逻辑处理
        3.1 根据编号去redis获取后端存储的图片验证码值
        3.2 对比用户填写的验证码值和后端的图片验证码值是否一致
        3.3 不一致：提示图片验证码错误
        3.4 一致：发送短信验证码
    4. 返回值处理
        4.1 获取短信验证码的返回值，告知前端发送短信的结果
    """
    # 1. 获取参数
    # request.data 获取数据就是json格式 {"mobile":18520340803, "image_code":"ASVS", "image_code_id":"xxx"}
    # params_dict = json.loads(request.data)
    # request.json 能够自动将json数据转换成python对象（字典或者列表）
    params_dict = request.json
    # 1.1 图片验证码真实值
    image_code = params_dict["image_code"]
    # 1.2 图片验证码的编号（UUID）
    image_code_id = params_dict["image_code_id"]
    # 1.3 手机号码
    mobile = params_dict["mobile"]

    # 2.1 判断参数是否有值
    if not all([mobile,image_code,image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 2.2 手机号码的格式进行正则匹配
    if not re.match("1[35678]\\d{9}", mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机号码格式错误")

    # 3.1 根据编号去redis获取后端存储的图片验证码值
    try:
        real_image_code = redis_store.get("ImageCodeId_" + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库查询图片验证码值错误")

    # 判断real_image_code是否有值
    if real_image_code is None:
        # 说明图片验证码过期
        return jsonify(errno=RET.NODATA, errmsg="图片验证码过期")

    # 3.2 对比用户填写的验证码值和后端的图片验证码值是否一致
    if image_code.upper() != real_image_code.upper():
        return jsonify(errno=RET.DATAERR, errmsg="图片验证码值填写错误")

    # 3.4 一致：发送短信验证码
    # 生成一个6位的短信验证码随机值 000045
    random_msg_code = "%06d" % random.randint(0,99999)
    # 打印短信验证码
    current_app.logger.debug(random_msg_code)


    # result = CCP().send_template_sms(mobile, [random_msg_code, constants.SMS_CODE_REDIS_EXPIRES/60], 1)
    # # 4.1 获取短信验证码的返回值，告知前端发送短信的结果
    # if result != 0:
    #     return jsonify(errno=RET.THIRDERR, errmsg="云通讯发送短信验证码失败")

    # 将短信验证码存储到redis
    try:
        redis_store.set("mobilesms_" + mobile, random_msg_code, ex=constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="存储短信验证码到redis出错")

    # 4.2 返回短信验证码成功的信息
    return jsonify(errno=RET.OK, errmsg="发送短信验证码成功")

@passport_bp.route("/image_code")
def get_image_code():
    """
    注册接口
    1. 获取参数
    2. 参数校验
        2.1 判断imageCodeId是否有值
    3. 业务逻辑处理
        3.1. 生成验证码图片和验证码真实值
        3.2. 保存验证码真实值到redis
    4. 处理返回值
        4.1. 返回验证码图片
    """

    #  1. 获取参数
    # args 是获取到url问号后面的参数
    imageCodeId = request.args.get("imageCodeId")

    # 2. 判断imageCodeId是否有值
    if imageCodeId is None:
        return abort(403)

    # 3.1.生成验证码图片和验证码真实值
    name,text,image = captcha.generate_captcha()

    current_app.logger.debug(text)


    # 3.2.保存验证码真实值到redis
    try:
        redis_store.set("ImageCodeId_" + imageCodeId, text, ex=constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        # 日记记录
        current_app.logger.error(e)
        return abort(500)


    # 4.1.返回验证码图片的响应对象
    response = make_response(image)
    # 设置响应格式
    response.headers["Content-Type"] = "image/jpg"
    return response





